package middleware

import (
	"bytes"
	"framework-server/global"
	"framework-server/model"
	"github.com/gin-gonic/gin"
	"github.com/go-kit/log/level"
	"github.com/sirupsen/logrus"
	"io/ioutil"
	"net/http"
	"time"
)

func OperationRecord() gin.HandlerFunc {
	return func(c *gin.Context) {
		var body []byte
		if c.Request.Method != http.MethodGet {
			var err error
			body, err = ioutil.ReadAll(c.Request.Body)
			if err != nil {
				level.Error(global.GVA_LOG).Log("msg", "read body from request error", "err", err)
			} else {
				c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
			}
		}

		userId := 0
		user, ok := c.Get("user")
		if ok {
			waitUse := user.(model.SysUser)
			userId = int(waitUse.ID)
		}
		record := model.SysOperationRecord{
			Ip:     c.ClientIP(),
			Method: c.Request.Method,
			Path:   c.Request.URL.Path,
			Agent:  c.Request.UserAgent(),
			Body:   string(body),
			UserID: userId,
		}
		writer := responseBodyWriter{
			ResponseWriter: c.Writer,
			body:           &bytes.Buffer{},
		}
		c.Writer = writer
		now := time.Now()

		c.Next()

		latency := time.Now().Sub(now)
		record.ErrorMessage = c.Errors.ByType(gin.ErrorTypePrivate).String()
		record.Status = c.Writer.Status()
		record.Latency = latency
		record.Resp = writer.body.String()
		record.Params = c.Request.URL.RawQuery

		global.GVA_APILOG.WithFields(logrus.Fields{
			"ip":            record.Ip,
			"method":        c.Request.Method,
			"path":          c.Request.URL.Path,
			"agent":         c.Request.UserAgent(),
			"body":          string(body),
			"params":        c.Request.URL.RawQuery,
			"user_id":       userId,
			"latency":       time.Now().Sub(now),
			"error_message": c.Errors.ByType(gin.ErrorTypePrivate).String(),
			"status":        c.Writer.Status(),
			"resp":          writer.body.String(),
		}).Info()

		//if err := service.CreateSysOperationRecord(record); err != nil {
		//	global.GVA_LOG.Error("create operation record error:", zap.Any("err", err))
		//}
	}
}

type responseBodyWriter struct {
	gin.ResponseWriter
	body *bytes.Buffer
}

func (r responseBodyWriter) Write(b []byte) (int, error) {
	r.body.Write(b)
	return r.ResponseWriter.Write(b)
}
